﻿using System;
using System.Speech.Synthesis;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DGRobot
{
    /// <summary>
    /// 机器人的驱动
    /// </summary>
    public class RobotDriver:IDisposable
    {

        private static RobotDriver _robotDriver;

        public static RobotDriver Instance
        {
            get
            {
                if(_robotDriver==null)
                    _robotDriver=new RobotDriver();
                return _robotDriver;
            }
        }
        public class SpeakStartEventArgs : EventArgs
        {
            public string CurrentStage { get; set; }
        }
        public class SpeakCompletedEventArgs : EventArgs
        {
            public string CurrentStage { get; set; }
            /// <summary>
            /// 是否是取消导致完成的
            /// </summary>
            public bool Cancelled { get; set; }
        }

        public class ListenStartEventArgs : EventArgs
        {
            public string CurrentStage { get; set; }
        }
        public class ListenCompletedEventArgs : EventArgs
        {
            public string CurrentStage { get; set; }
            public bool IsSuccess { get; set; }
            public string ErrorMessage { get; set; }
            public string HearTheWord { get; set; }
        }
        public class ListeningEventArgs : EventArgs
        {
            public string CurrentStage { get; set; }
            public string HearTheWord { get; set; }

        }
        private SpeechSynthesizer synth = new SpeechSynthesizer();
        private Prompt _currentPrompt;
        private YZH.Audio.Disting.RecorderDisting _recorderDistingDriver = new YZH.Audio.Disting.RecorderDisting();

        public delegate void OnStartListenHandler(ListenStartEventArgs args);
        public delegate void OnStartSpeakHandler(SpeakStartEventArgs args);
        public delegate void OnListeningHandler(ListeningEventArgs args);
        public delegate void OnListenCompletedHandler(ListenCompletedEventArgs args);
        public delegate void OnSpeakCompletedHandler(SpeakCompletedEventArgs args);

        public OnSpeakCompletedHandler OnSpeakCompleted;
        public OnStartSpeakHandler OnSpeakStart;
        public OnListenCompletedHandler OnListenCompleted;
        public OnListeningHandler OnListening;
        public OnStartListenHandler OnListenStart;

        private string _currentStage = "";
        private bool _isSpeaking = false; //是否正在说
        private bool _isListening = false;//是否正在听
        public RobotDriver()
        {
            LogHelper.Log("机器人启动");
            this.synth.SpeakCompleted += Synth_SpeakCompleted;
            this._recorderDistingDriver.OnMessage = OnMessage;
            ChangeVoice(Config.TTSName);
        }

        public void ChangeVoice(string name)
        {
            try
            {
                if (!string.IsNullOrEmpty(name))
                {
                    synth.SelectVoice(name);
                }
            }
            catch
            {
            }
        }

        private void Synth_SpeakCompleted(object sender, System.Speech.Synthesis.SpeakCompletedEventArgs e)
        {
            LogHelper.Log("机器人说完了" );
            this._isSpeaking = false;
            var stage = this._currentStage;
            this._currentStage = "";
            _currentPrompt = null;
            
            if (_isSpeakCallBack)
            {
                if (OnSpeakCompleted != null)
                {
                    OnSpeakCompleted(new SpeakCompletedEventArgs
                    {
                        Cancelled = e.Cancelled,
                        CurrentStage = stage
                    });
                }
            }
            else
            {
                _isSpeakCallBack = true;
            }
        }
        private readonly StringBuilder _hearTheWords=new StringBuilder(1024);
        private void OnMessage(object o, string msg, bool isStop)
        {
            if (isStop)
            {
                this._isListening = false;
                var isSuccess = msg == "done";
                var hearTheword = _hearTheWords.ToString();
                _hearTheWords.Clear();
                LogHelper.Log("机器人听到"+ msg + ":" + hearTheword);
                if (OnListenCompleted != null)
                {
                    Task.Factory.StartNew(() =>
                    {
                        OnListenCompleted(new ListenCompletedEventArgs
                        {
                            CurrentStage = this._currentStage,
                            HearTheWord = hearTheword,
                            IsSuccess = isSuccess,
                            ErrorMessage = msg
                        });
                    });
                }
                
            }
            else
            {
                LogHelper.Log("机器人听到:" + msg);
                _hearTheWords.Append(msg);
                if (OnListening != null)
                {
                    Task.Factory.StartNew(() =>
                    {
                        OnListening(new ListeningEventArgs
                        {
                            CurrentStage = this._currentStage,
                            HearTheWord = msg
                        });
                    });
                }
            }
        }
        
        /// <summary>
        /// 开始说
        /// </summary>
        /// <param name="stageKey">说话的场景</param>
        /// <param name="text"></param>
        public void StartSpeak(string stageKey,string text)
        {
            lock (_lockSpeaking)
            {
                if (_isSpeaking)
                {
                    StopSpeak();
                }
                LogHelper.Log("机器人开始说话:" + stageKey + "\t" + text);
                Task.Factory.StartNew(() =>
                {
                    //停止当前说的
                    _currentPrompt = synth.SpeakAsync(text);
                    _isSpeaking = true;
                    _currentStage = stageKey;
                    if (OnSpeakStart != null)
                    {
                        OnSpeakStart(new SpeakStartEventArgs
                        {
                            CurrentStage = stageKey
                        });
                    }
                }, TaskCreationOptions.LongRunning);
            }
        }

        private Task<bool> _speakCompleteTask;

        private bool _isSpeakCallBack=true;

        public void StopSpeak(bool isCallBack = true)
        {
            lock (_lockSpeaking)
            {
                if (!_isSpeaking) return;
                if (_currentPrompt == null) return;
                _isSpeakCallBack = isCallBack;
                LogHelper.Log("机器人不说了");
                _isSpeaking = false;
                
                synth.SpeakAsyncCancel(_currentPrompt);
                _currentPrompt = null;
            }
        }

        private object _lockListen = new object();
        private object _lockSpeaking = new object();
        /// <summary>
        /// 开始听
        /// </summary>
        public void StartListen(string stageKey)
        {
            lock (_lockListen)
            {
                if (_isListening)
                {
                    StopListen();
                }

                Thread.Sleep(200);
                LogHelper.Log("机器人开始听:" + stageKey);
                _recorderDistingDriver.Start();
                _isListening = true;
                _currentStage = stageKey;
                if (OnListenStart != null)
                {
                    Task.Factory.StartNew(() =>
                    {
                        OnListenStart(new ListenStartEventArgs
                        {
                            CurrentStage = stageKey
                        });
                    });
                }
            }
        }

        public void StopListen()
        {
            lock (_lockListen)
            {
                if (!_isListening) return;
                LogHelper.Log("机器人不听了");
                _isListening = false;
                _recorderDistingDriver.Stop();
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (_robotDriver == null) return;
            LogHelper.Log("机器人关闭");
            _isListening = false;
            _isSpeaking = false;
            
            this.synth.Dispose();
            this._recorderDistingDriver.Dispose();
            _robotDriver = null;
        }
    }
}